
package com.ru.application.creditscore.domain;

import static javax.persistence.CascadeType.PERSIST;
import static javax.persistence.FetchType.LAZY;
import static org.hibernate.annotations.CacheConcurrencyStrategy.NONSTRICT_READ_WRITE;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.Digits;
import org.apache.log4j.Logger;
import org.hibernate.annotations.Cache;
import com.google.common.base.Objects;
import com.ru.application.creditscore.domain.IdentifiableHashBuilder;
import com.ru.application.creditscore.domain.ScoringFactor;
import com.ru.application.creditscore.domain.ScoringSchema;

@Entity
@Table(name = "SCORING_RULE")
@Cache(usage = NONSTRICT_READ_WRITE)
public class ScoringRule implements Identifiable<Integer>, Serializable {
    private static final long serialVersionUID = 1L;
    private static final Logger log = Logger.getLogger(ScoringRule.class);

    // Raw attributes
    private Integer id; // pk
    private Double weight;

    // Technical attributes for query by example
    private Integer schemaId;
    private Integer factorId;

    // Many to one
    private ScoringSchema schema; // (schemaId)
    private ScoringFactor factor; // (factorId)

    // ---------------------------
    // Constructors
    // ---------------------------

    public ScoringRule() {
    }

    public ScoringRule(Integer primaryKey) {
        setId(primaryKey);
    }

    // -------------------------------
    // Getter & Setter
    // -------------------------------

    // -- [id] ------------------------

    @Column(name = "id", precision = 10)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="scoring_rule_id_seq")
    @SequenceGenerator(name="scoring_rule_id_seq", sequenceName="scoring_rule_id_seq",allocationSize=1)
    @Id
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Transient
    public boolean isIdSet() {
        return id != null;
    }

    // -- [schemaId] ------------------------

    @Column(name = "schema_id", precision = 10, insertable = false, updatable = false)
    public Integer getSchemaId() {
        return schemaId;
    }

    private void setSchemaId(Integer schemaId) {
        this.schemaId = schemaId;
    }

    // -- [factorId] ------------------------

    @Column(name = "factor_id", precision = 10, insertable = false, updatable = false)
    public Integer getFactorId() {
        return factorId;
    }

    private void setFactorId(Integer factorId) {
        this.factorId = factorId;
    }

    // -- [weight] ------------------------

    @Digits(integer = 9, fraction = 3)
    @Column(name = "weight", precision = 9, scale = 3)
    public Double getWeight() {
        return weight;
    }

    public void setWeight(Double weight) {
        this.weight = weight;
    }

    // --------------------------------------------------------------------
    // Many to One support
    // --------------------------------------------------------------------

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // many-to-one: ScoringRule.schemaId ==> ScoringSchema.id
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    @Cache(usage = NONSTRICT_READ_WRITE)
    @JoinColumn(name = "schema_id")
    @ManyToOne(cascade = PERSIST, fetch = LAZY)
    public ScoringSchema getSchema() {
        return schema;
    }

    /**
     * Set the schema without adding this ScoringRule instance on the passed schema
     * If you want to preserve referential integrity we recommend to use
     * instead the corresponding adder method provided by {@link ScoringSchema}
     */
    public void setSchema(ScoringSchema schema) {
        this.schema = schema;

        // We set the foreign key property so it can be used by our JPA search by Example facility.
        if (schema != null) {
            setSchemaId(schema.getId());
        } else {
            setSchemaId(null);
        }
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // many-to-one: ScoringRule.factorId ==> ScoringFactor.id
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    @Cache(usage = NONSTRICT_READ_WRITE)
    @JoinColumn(name = "factor_id")
    @ManyToOne(cascade = PERSIST, fetch = LAZY)
    public ScoringFactor getFactor() {
        return factor;
    }

    /**
     * Set the factor without adding this ScoringRule instance on the passed factor
     * If you want to preserve referential integrity we recommend to use
     * instead the corresponding adder method provided by {@link ScoringFactor}
     */
    public void setFactor(ScoringFactor factor) {
        this.factor = factor;

        // We set the foreign key property so it can be used by our JPA search by Example facility.
        if (factor != null) {
            setFactorId(factor.getId());
        } else {
            setFactorId(null);
        }
    }

    /**
     * Set the default values.
     */
    public void initDefaultValues() {
    }

    /**
     * equals implementation using a business key.
     */
    @Override
    public boolean equals(Object other) {
        return this == other || (other instanceof ScoringRule && hashCode() == other.hashCode());
    }

    private IdentifiableHashBuilder identifiableHashBuilder = new IdentifiableHashBuilder();

    @Override
    public int hashCode() {
        return identifiableHashBuilder.hash(log, this);
    }

    /**
     * Construct a readable string representation for this ScoringRule instance.
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return Objects.toStringHelper(this) //
                .add("id", getId()) //
                .add("schemaId", getSchemaId()) //
                .add("factorId", getFactorId()) //
                .add("weight", getWeight()) //
                .toString();
    }

}